home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / util / arc / CheckX.lha / CheckX / sources / CheckX.c next >
C/C++ Source or Header  |  1999-02-11  |  50KB  |  1,707 lines

  1. #define NAME         "CheckX"
  2. #define REVISION     "47"
  3. #define DISTRIBUTION "(Freeware) "
  4.  
  5. /*
  6. When someone uses the here shown methods for own programs, he has to
  7. contact me first and always to mention me in his program documentation!
  8.  
  9. This program scans for crunched, linked files and archived files. It
  10. decrunches them and saves the result files to another directory-tree.
  11. The scanning routines are recursiv and thus check really all stuff. Linked
  12. files are saved with .1, .2, ... additions.
  13.  
  14. The main purpose it was written for is to scan for crunched files and to
  15. test the decrunch routines. So the logging may take some more time, but is
  16. very stable, as the last log-entry is always the file which possibly
  17. crashed the machine.
  18.  
  19. Address crunched programs are decrunched as well, but not saved. Use
  20. xfdDecrunch or xfdDecrunchAddr to generate decrunched executable files
  21. of this type (with correct header information).
  22.  
  23. Especially in UNARCHIVE mode this tool may need lots of memory (when T: is
  24. assigned to ram disk). Keep that in mind! Every checked file is completely
  25. loaded into memory!
  26.  
  27. CheckX cannot scan files, which are read-protected. You get CheckX error 106
  28. as result in that case. Unprotect files and scan again when you want.
  29.  
  30. NOTE: SaveDir must exist already, only sub-dirs are created.
  31.  
  32. The program must be compiled and linked without startup-code. You can set
  33. the pure file protection bit and make it resident, because it is multi-
  34. reentrant (no global variables, except library bases).
  35. This means it can be called multiple times as well, but this is not
  36. recommended, as said above CheckX needs lots of memory.
  37.  
  38. Disk archives are handled this way:
  39. They are unarchived to RD0: in depth1, to RD1: in depth2 (when archive is
  40. in RD0:) and to RD2: in depth3, ....
  41.  
  42. NOTE: accessing RD0:, RD1 or RD2: during this time may produce errors.
  43. This includes starting CheckX twice, when scanning disk archives. For high
  44. density archives the archive names are RH1:, RH2:, ...
  45.  
  46. Splitted DMS-Archives may produce strange errors, but can be checked
  47. correctly, when the two parts are directly after another (e.g. no other
  48. track archive is between them). In this case the first file shows some
  49. XPKCERR_READWRITE and the second one the correct stuff.
  50.  
  51. Crypted archives are not supported yet (e.g. asking for password).
  52. */
  53.  
  54. /* Programmheader
  55.  
  56.     Name:        CheckX
  57.     Author:        SDI
  58.     Distribution:    Freeware
  59.     Description:    scans and decrunches crunched files with xfd
  60.     Compileropts:    -
  61.     Linkeropts:    -l xpkmaster amiga -gsi
  62.     Plans:        add new archivers, xadmaster.library support
  63.  
  64.  1.0   14.12.96 : first Version
  65.  1.1   28.12.96 : moved PassRequest into xpkmaster.library
  66.  1.2   12.02.97 : now also decrunches Exe-Files
  67.  1.3   15.06.97 : added length output as test
  68.  1.4   21.11.97 : renamed from Decrunch, got really new program
  69.  1.5   22.11.97 : bug-fixes
  70.  1.6   29.11.97 : added unarchiving feature
  71.  1.7   30.11.97 : bug-fixes
  72.  1.8   06.12.97 : xpkmaster.library now only required with ASKPWD option
  73.  1.9   07.12.97 : Added archive copy for weird archive names, better error
  74.     codes
  75.  1.10  08.12.97 : fixed error codes a bit
  76.  1.11  11.12.97 : disabled DOS requests, added Zip-Archives, added TaskID
  77.     to temporary filenames
  78.  1.12  12.12.97 : added Arc, ZOO and LhASFX archives
  79.  1.13  13.12.97 : fixed Arc recognition
  80.  1.14  19.12.97 : deletes copied arc before scan
  81.  1.15  22.12.97 : crunched archives are unarchived correctly now
  82.  1.16  02.01.98 : opens dos.library itself, no startup-code required
  83.  1.17  23.01.98 : added disk crunchers
  84.  1.18  24.01.98 : some fixes
  85.  1.19  01.02.98 : little bug-fix in argument-option use
  86.  1.20  06.02.98 : better error output, added automount
  87.  1.21  08.02.98 : little bug-fix
  88.  1.22  10.02.98 : fixed archive copy conditions, added PRINTALL
  89.  1.23  12.02.98 : fixed help text, bug fixes with unlinking and FreeMem
  90.  1.24  13.02.98 : added unstripping
  91.  1.25  04.03.98 : added PRINTEXEC
  92.  1.26  13.03.98 : added high density DMS support
  93.  1.27  19.03.98 : added LOUD keyword
  94.  1.28  23.03.98 : RDx no longer depends on archive depth, but on dddepth
  95.  1.29  10.04.98 : bug fixes
  96.  1.30  26.04.98 : bug fixes
  97.  1.31  09.05.98 : now uses no longer adress 4 for SysBase
  98.  1.32  31.05.98 : better output
  99.  1.33  04.06.98 : added HEADER addition for address files
  100.  1.34  08.08.98 : bug fix with SAVE
  101.  1.35  24.09.98 : added xvs.library virus checks
  102.  1.36  18.10.98 : xvs is opened global and only once
  103.  1.37  30.10.98 : renamed from CheckXFD
  104.  1.38  11.11.98 : fixed format drive bug using a delay and an error report
  105.  1.39  14.11.98 : format error with AUTOMOUNT removed
  106.  1.40  16.11.98 : removed HEADER addition stuff
  107.  1.41  18.11.98 : better RDx: access and mount
  108.  1.42  23.11.98 : fixed bug with hunk stripping
  109.  1.43  29.12.98 : now prints an error, when virus detection is turned off,
  110.     added time calculation and output
  111.  1.44  31.12.98 : little bug fix
  112.  1.45  06.02.99 : bug fixes, added xadmaster.library stuff, removed LOUD
  113.     and internal DMS call
  114.  1.46  09.02.99 : removed internal LZX call
  115.  1.47  11.02.99 : now uses assembler startcode allocating a bigger stack
  116. */
  117.  
  118. #include <proto/exec.h>
  119. #include <proto/dos.h>
  120. #include <proto/xfdmaster.h>
  121. #include <proto/xadmaster.h>
  122. #include <proto/xpkmaster.h>
  123. #include <proto/intuition.h>
  124. #include <proto/xvs.h>
  125. #include <libraries/xfdmaster.h>
  126. #include <dos/dostags.h>
  127. #include <dos/doshunks.h>
  128. #include <exec/memory.h>
  129. #include "SDI_defines.h" /* make version string */
  130.  
  131. #define SDI_TO_ANSI
  132. #include "SDI_ASM_STD_protos.h"
  133.  
  134. #define PARAM   "FROM,LOG,SAVE/K,ALL/S,ASKPWD/S,AUTOMOUNT/S,PRINTALL/S," \
  135.         "PRINTEXEC/S,"                 \
  136.         "NODECRUNCH/S,NOUNLINK/S,NOUNARCHIVE/S,NOUNTRACK/S,"     \
  137.         "NOTRACKCUT/S,NOSTRIP/S,NOVIRUS/S"
  138.  
  139. #ifdef __SASC
  140.   #define XpkBase    xpkbase
  141.   #define ASSIGN_XPK
  142.   #define IntuitionBase    intuitionbase
  143.   #define ASSIGN_INT
  144. #else
  145.   struct Library *    XpkBase        = 0;
  146.   struct IntuitionBase *IntuitionBase    = 0;
  147.   #define ASSIGN_XPK    XpkBase = xpkbase;
  148.   #define ASSIGN_INT    IntuitionBase = intuitionbase;
  149. #endif
  150. struct xfdMasterBase *    xfdMasterBase    = 0;
  151. struct DosLibrary *    DOSBase        = 0;
  152. struct ExecBase *    SysBase        = 0;
  153. struct xvsBase *    xvsBase        = 0;
  154. struct xadMasterBase *    xadMasterBase    = 0;
  155.  
  156. struct Args {
  157.   STRPTR from;
  158.   STRPTR log;
  159.   STRPTR save;
  160.   ULONG  all;
  161.   ULONG  askpwd;
  162.   ULONG  automount;
  163.   ULONG  printall;
  164.   ULONG  printexec;
  165.   ULONG  nodecrunch;
  166.   ULONG  nounlink;
  167.   ULONG  nounarchive;
  168.   ULONG  nountrack;
  169.   ULONG  notrackcut;
  170.   ULONG  nostrip;
  171.   ULONG  novirus;
  172. };
  173.  
  174. struct CrunchMemList {
  175.   struct CrunchMemList * cml_Next;
  176.   APTR             cml_MemoryRegion;
  177.   ULONG             cml_MemorySize;
  178. };
  179.  
  180. #define XFDCHECKFLAG_SAVE        (1<< 0)
  181. #define XFDCHECKFLAG_ALL        (1<< 1)
  182. #define XFDCHECKFLAG_ASKPWD        (1<< 2)
  183. #define XFDCHECKFLAG_AUTOMOUNT        (1<< 3)
  184. #define XFDCHECKFLAG_PRINTALL        (1<< 4)
  185. #define XFDCHECKFLAG_PRINTEXEC        (1<< 5)
  186. #define XFDCHECKFLAG_NODECRUNCH        (1<< 6)
  187. #define XFDCHECKFLAG_NOUNLINK        (1<< 7)
  188. #define XFDCHECKFLAG_NOUNARCHIVE    (1<< 8)
  189. #define XFDCHECKFLAG_NOUNTRACK        (1<< 9)
  190. #define XFDCHECKFLAG_NOTRACKCUT        (1<<10)
  191. #define XFDCHECKFLAG_NOSTRIP        (1<<11)
  192.  
  193. #define XFDCHECKFLAG_XVSLIB        (1<<15)
  194. #define XFDCHECKFLAG_XADLIB        (1<<16)
  195.  
  196. #define XFDCALLFLAGS    (XFDCHECKFLAG_SAVE|XFDCHECKFLAG_ALL|          \
  197.              XFDCHECKFLAG_ASKPWD|XFDCHECKFLAG_AUTOMOUNT|      \
  198.              XFDCHECKFLAG_PRINTALL|XFDCHECKFLAG_PRINTEXEC|      \
  199.              XFDCHECKFLAG_NODECRUNCH|XFDCHECKFLAG_NOUNLINK|   \
  200.              XFDCHECKFLAG_NOUNARCHIVE|XFDCHECKFLAG_NOUNTRACK| \
  201.              XFDCHECKFLAG_NOTRACKCUT|XFDCHECKFLAG_NOSTRIP|      \
  202.              XFDCHECKFLAG_XVSLIB|XFDCHECKFLAG_XADLIB)
  203.  
  204. #define XFDSAVEFLAGS    (XFDCHECKFLAG_LINKED|XFDCHECKFLAG_CRUNCHED|      \
  205.              XFDCHECKFLAG_STRIPPED)
  206.  
  207. #define XFDCHECKFLAG_NAMEPRINTED    (1<<20)
  208. #define XFDCHECKFLAG_CRUNCHED        (1<<21)
  209. #define XFDCHECKFLAG_LINKED        (1<<22)
  210. #define XFDCHECKFLAG_ADDRESS        (1<<23)
  211. #define XFDCHECKFLAG_NOFREEMEM        (1<<24)
  212. #define XFDCHECKFLAG_STRIPPED        (1<<25)
  213. #define XFDCHECKFLAG_HIGHDENSITY    (1<<26)
  214.  
  215. #define XADERR_OFFSET        0x100
  216. #define XFDERR_OFFSET        0x200
  217.  
  218. #define XFDCERR_NOMEMORY    1
  219. #define XFDCERR_EXAMINEERR    2
  220. #define XFDCERR_OPENERR        3
  221. #define XFDCERR_READWRITE    4
  222. #define XFDCERR_SCANERR        5
  223. #define XFDCERR_BREAK        6
  224. #define XFDCERR_OPENDIR        7
  225. #define XFDCERR_NORAD        8
  226. #define XFDCERR_NODOS        9 /* not a dos disk */
  227. #define XFDCERR_RESOURCE    10
  228. #define XFDCERR_NOVIRUS        11
  229.  
  230. struct FileData {
  231.   struct CrunchMemList * fd_MemList;
  232.   STRPTR         fd_Name;
  233.   ULONG           fd_LogFileFH;
  234.   ULONG           fd_SaveDirL;
  235.   ULONG             fd_Flags;
  236.   ULONG             fd_NumVirus;
  237.   UBYTE           fd_RecurseDepth;
  238.   UBYTE           fd_LinkNum;
  239.   UBYTE             fd_ArchiveDepth;
  240.   UBYTE             fd_DDDepth;
  241.   UBYTE             fd_HDDepth;
  242. };
  243.  
  244. LONG DoDirectoryScan(STRPTR, STRPTR, struct FileData *);
  245. LONG DoFileOpen(struct FileData *);
  246. void DoMount(ULONG, ULONG);
  247. BPTR GetRad(struct FileData *, STRPTR);
  248. LONG CallSystem(STRPTR);
  249. LONG DoGetVirus(struct FileData *, APTR, ULONG);
  250. LONG DoFileUnArchive(struct FileData *, APTR, ULONG);
  251. LONG DoFileUnLink(struct FileData *, APTR, ULONG);
  252. LONG DoFileUnCrunch(struct FileData *, APTR, ULONG);
  253. LONG DoFileStrip(struct FileData *, APTR, ULONG);
  254. void PrintXFDFile(struct FileData *);
  255. void PrintXFDErr(struct FileData *, LONG);
  256. void PrintXFDTxt(struct FileData *, STRPTR, ...);
  257. LONG AddCrunchMemList(struct FileData *, APTR, ULONG);
  258. void FreeCrunchMemList(struct FileData *, APTR);
  259. LONG SaveUncrFile(struct FileData *, APTR, ULONG);
  260. ULONG OpenParentDir(struct FileData *);
  261. ULONG OpenNewDir(struct FileData *, STRPTR);
  262.  
  263. /* All memory regions must be in mem list. All unneeded memory must be freed
  264.    as fast as possible (after unlinking, decrunching), as well as the
  265.    MemoryList structure.
  266.    
  267.    The program has a loop like scan routine system, which is called for
  268.    every file:
  269.  
  270.    A) Scan files, directories and sub directories and call following for
  271.       every file:
  272.    1) Check for viruses.
  273.    2) Test if it is an archive. When yes decrunch and start with point A.
  274.    3) Test if file is linked. When yes unlink and call point 1 for both
  275.       parts.
  276.    4) Test if file is crunched. When yes, decrunch and start again with
  277.       point 1.
  278.    5) Try stripping useless stuff. When succesful start with point 1 again.
  279.    6) Possibly save file (with SAVE option) or end loop here.
  280. */
  281.  
  282. /* main routine, do argument parsing */
  283. LONG start(void)
  284. {
  285.   LONG error = RETURN_FAIL;
  286.   struct DosLibrary *dosbase;
  287.   struct Process *task;
  288.  
  289.   SysBase = (*((struct ExecBase **) 4));
  290.  
  291.   /* test for WB and reply startup-message */
  292.   if(!(task = (struct Process *) FindTask(0))->pr_CLI)
  293.   {
  294.     WaitPort(&task->pr_MsgPort);
  295.     Forbid();
  296.     ReplyMsg(GetMsg(&task->pr_MsgPort));
  297.     return RETURN_FAIL;
  298.   }
  299.  
  300.   if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  301.   {
  302.     struct xfdMasterBase *xfdmasterbase;
  303.  
  304.     DOSBase = dosbase;
  305.  
  306.     if((xfdmasterbase = (struct xfdMasterBase *)
  307.     OpenLibrary("xfdmaster.library", 37)))
  308.     {
  309.       struct Args Args;
  310.       struct RDArgs *rda;
  311.  
  312.       xfdMasterBase = xfdmasterbase;
  313.  
  314.       memset(&Args, 0, sizeof(struct Args));
  315.  
  316.       if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
  317.       {
  318.         rda->RDA_ExtHelp =
  319.         "FROM        source file or directory - may contain patterns\n"
  320.         "LOG         log file name\n"
  321.         "SAVE        directory, where decrunched files are saved\n"
  322.         "ALL         scan deep into directories\n"
  323.         "ASKPWD      ask for password when needed (needs xpkmaster.library)\n"
  324.     "PRINTALL    print all filenames\n"
  325.         "PRINTEXEC   print names of all executable files\n"
  326.     "AUTOMOUNT   automatically mount RDx: device when needed\n"
  327.         "NODECRUNCH  do not decrunch files with xfdmaster\n"
  328.         "NOUNLINK    do not unlink files with xfdmaster\n"
  329.         "NOUNARCHIVE do not call archiver for unarchiving file archives\n"
  330.         "NOUNTRACK   do not call archiver for unarchiving track archives\n"
  331.         "NOTRACKCUT  do not call archiver for partially track archives\n"
  332.         "NOSTRIP     do not strip useless hunks\n"
  333.         "NOVIRUS     do not scan with xvs.library for viruses\n";
  334.         if(ReadArgs(PARAM, (LONG *) &Args, rda))
  335.         {
  336.           ULONG flags = 0, log = 0;
  337.           struct xvsBase *xvsbase = 0;
  338.           struct xadMasterBase *xadmasterbase = 0;
  339.  
  340.           if(!Args.from)    Args.from = "#?";
  341.           if(Args.all)        flags |= XFDCHECKFLAG_ALL;
  342.           if(Args.save)        flags |= XFDCHECKFLAG_SAVE;
  343.           if(Args.askpwd)    flags |= XFDCHECKFLAG_ASKPWD;
  344.           if(Args.automount)    flags |= XFDCHECKFLAG_AUTOMOUNT;
  345.       if(Args.printall)    flags |= XFDCHECKFLAG_PRINTALL;
  346.       if(Args.printexec)    flags |= XFDCHECKFLAG_PRINTEXEC;
  347.           if(Args.nodecrunch)    flags |= XFDCHECKFLAG_NODECRUNCH;
  348.           if(Args.nounlink)     flags |= XFDCHECKFLAG_NOUNLINK;
  349.           if(Args.nounarchive)    flags |= XFDCHECKFLAG_NOUNARCHIVE;
  350.           if(Args.nountrack)    flags |= XFDCHECKFLAG_NOUNTRACK;
  351.           if(Args.notrackcut)    flags |= XFDCHECKFLAG_NOTRACKCUT;
  352.           if(Args.nostrip)    flags |= XFDCHECKFLAG_NOSTRIP;
  353.           if(!Args.novirus)
  354.           {
  355.             if((xvsbase = (struct xvsBase *) OpenLibrary("xvs.library", 33)))
  356.             {
  357.               flags |= XFDCHECKFLAG_XVSLIB;
  358.               xvsBase = xvsbase;
  359.             }
  360.       }
  361.       if(!Args.nounarchive || !Args.nountrack)
  362.       {
  363.         if((xadmasterbase = (struct xadMasterBase *) OpenLibrary("xadmaster.library", 1)))
  364.         {
  365.           flags |= XFDCHECKFLAG_XADLIB;
  366.           xadMasterBase = xadmasterbase;
  367.         }
  368.       }
  369.  
  370.           if(!Args.log || (log = Open(Args.log, MODE_READWRITE)))
  371.           {
  372.         struct FileData fd;
  373.         APTR win;
  374.         ULONG s1 = 0, s2 = 0, msecs;
  375.         struct IntuitionBase *intuitionbase;
  376.  
  377.         win = task->pr_WindowPtr;
  378.         task->pr_WindowPtr = (APTR) -1;
  379.         /* prevent dos requests */
  380.  
  381.         if(log)
  382.           SetFileSize(log, 0, OFFSET_BEGINNING);
  383.  
  384.         memset(&fd, 0, sizeof(struct FileData));
  385.             fd.fd_Flags = flags;
  386.             fd.fd_LogFileFH = log;
  387.  
  388.         if(!xvsbase)
  389.         {
  390.           Printf("Virus-Checking disabled!\n");
  391.           if(log)
  392.             FPrintf(log, "Virus-Checking disabled!\n");
  393.         }
  394.  
  395.         if((intuitionbase = (struct IntuitionBase *) OpenLibrary("intuition.library", 37)))
  396.         {
  397.           ASSIGN_INT
  398.           CurrentTime(&s1, &msecs);
  399.         }    
  400.  
  401.         error = DoDirectoryScan(Args.from, Args.save, &fd);
  402.  
  403.         task->pr_WindowPtr = win;
  404.  
  405.         if(intuitionbase)
  406.         {
  407.           CurrentTime(&s2, &msecs);
  408.           s2 -= s1;
  409.           s1 = s2 / 60;
  410.           s2 %= 60;
  411.           msecs = s1 / 60;
  412.           s1 %= 60;
  413.           Printf("\nTime needed for check: %2ld:%02ld:%02ld\n", msecs, s1, s2);
  414.           if(log)
  415.             FPrintf(log, "\nTime needed for check: %2ld:%02ld:%02ld\n", msecs, s1, s2);
  416.           
  417.           CloseLibrary((struct Library *) intuitionbase);
  418.         }
  419.         if(fd.fd_NumVirus)
  420.         {
  421.           Printf("The scan detected %ld virus%s.\n", fd.fd_NumVirus, fd.fd_NumVirus > 1 ? "es" : "");
  422.           if(log)
  423.             FPrintf(log, "The scan detected %ld virus%s.\n", fd.fd_NumVirus, fd.fd_NumVirus > 1 ? "es" : "");
  424.         }
  425.  
  426.             if(log)
  427.               Close(log);
  428.           }
  429.  
  430.       if(xvsbase)
  431.         CloseLibrary((struct Library *) xvsbase);
  432.       if(xadmasterbase)
  433.         CloseLibrary((struct Library *) xadmasterbase);
  434.           FreeArgs(rda);
  435.         }
  436.         FreeDosObject(DOS_RDARGS, rda);
  437.       }
  438.       CloseLibrary((struct Library *) xfdmasterbase);
  439.     }
  440.     CloseLibrary((struct Library *) dosbase);
  441.   }
  442.  
  443.   return (error ? RETURN_FAIL : RETURN_OK);
  444. }
  445.  
  446. /* This scans a directory and calls DoFileOpen for every file. It
  447.    automatically creates SAVE destination directories when necessary. */
  448. LONG DoDirectoryScan(STRPTR name, STRPTR sav, struct FileData *fd)
  449. {
  450.   struct AnchorPath *APath;
  451.   LONG error = XFDCERR_SCANERR;
  452.   ULONG retval;
  453.  
  454.   if(!(fd->fd_Flags & XFDCHECKFLAG_SAVE) || !sav ||
  455.   (fd->fd_SaveDirL = Lock(sav, SHARED_LOCK)))
  456.   {
  457.     if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath) +
  458.     512, MEMF_PUBLIC|MEMF_CLEAR)))
  459.     {
  460.       fd->fd_Name = APath->ap_Buf;
  461.       APath->ap_Strlen = 256;
  462.       for(retval = MatchFirst(name, APath); !retval;
  463.       retval = MatchNext(APath))
  464.       {
  465.         if(APath->ap_Flags & APF_DIDDIR)
  466.         {
  467.           OpenParentDir(fd);
  468.           APath->ap_Flags &= ~APF_DIDDIR; /* clear flag */
  469.         }
  470.         else if(APath->ap_Info.fib_DirEntryType > 0)
  471.         {
  472.           if(fd->fd_Flags & XFDCHECKFLAG_ALL)
  473.           {
  474.             OpenNewDir(fd, APath->ap_Info.fib_FileName);
  475.             APath->ap_Flags |= APF_DODIR;
  476.           }
  477.         }
  478.         else
  479.         {
  480.           PrintXFDErr(fd, DoFileOpen(fd));
  481.       fd->fd_Flags &= XFDCALLFLAGS;
  482.           fd->fd_LinkNum = 0;
  483.  
  484.           while(fd->fd_MemList)
  485.             FreeCrunchMemList(fd, fd->fd_MemList->cml_MemoryRegion);
  486.         }
  487.         if((fd->fd_Flags & XFDCHECKFLAG_SAVE) && !fd->fd_SaveDirL)
  488.         {
  489.           error = XFDCERR_OPENDIR; break;
  490.         }
  491.         if(CTRL_C)
  492.         {
  493.           error = XFDCERR_BREAK; break;
  494.         }
  495.       }
  496.       MatchEnd(APath);
  497.  
  498.       if(retval == ERROR_NO_MORE_ENTRIES)
  499.         error = 0;
  500.  
  501.       FreeMem(APath, sizeof(struct AnchorPath) + 512);
  502.     }
  503.     else
  504.       error = XFDCERR_NOMEMORY;
  505.  
  506.     if(sav && fd->fd_SaveDirL)
  507.       UnLock(fd->fd_SaveDirL);
  508.   }
  509.   else
  510.     error = XFDCERR_OPENDIR;
  511.  
  512.   return error;
  513. }
  514.  
  515. /* Open a file and call DoGetVirus to scan */
  516. LONG DoFileOpen(struct FileData *fd)
  517. {
  518.   struct FileInfoBlock *fib;
  519.   LONG ret = 0;
  520.  
  521.   if((fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
  522.   {
  523.     ULONG fh;
  524.  
  525.     if(fd->fd_ArchiveDepth) /* prevent scan errors */
  526.       SetProtection(fd->fd_Name, 0); /* set RWED bits */
  527.     if((fh = Open(fd->fd_Name, MODE_OLDFILE)))
  528.     {
  529.       if(ExamineFH(fh, fib))
  530.       {
  531.         APTR mem;
  532.  
  533.     if(!fib->fib_Size)
  534.           ;
  535.         else if((mem = AllocMem(fib->fib_Size, MEMF_ANY)))
  536.         {
  537.           if(Read(fh, mem, fib->fib_Size) != fib->fib_Size)
  538.             ret = XFDCERR_READWRITE;
  539.           else if(!(ret = AddCrunchMemList(fd, mem, fib->fib_Size)))
  540.           {
  541.             if((fd->fd_Flags & XFDCHECKFLAG_PRINTALL) ||
  542.             ((fd->fd_Flags & XFDCHECKFLAG_PRINTEXEC) && fib->fib_Size > 4
  543.             && *((ULONG *)mem) == HUNK_HEADER))
  544.               PrintXFDFile(fd);
  545.             ret = DoGetVirus(fd, mem, fib->fib_Size);
  546.           }
  547.         }
  548.         else
  549.           ret = XFDCERR_NOMEMORY;
  550.       }
  551.       else
  552.         ret = XFDCERR_EXAMINEERR;
  553.       Close(fh);
  554.     }
  555.     else
  556.       ret = XFDCERR_OPENERR;
  557.   
  558.     FreeDosObject(DOS_FIB, fib);
  559.   }
  560.   else
  561.     ret = XFDCERR_NOMEMORY;
  562.  
  563.   return ret;
  564. }
  565.  
  566. /* for SAVE option: open parent directory and try to delete the directory
  567.    we leave. This only succeeds, when the directory is empty. */
  568. ULONG OpenParentDir(struct FileData *fd)
  569. {
  570.   ULONG g;
  571.   UBYTE name[300];
  572.  
  573.   if((g = fd->fd_SaveDirL))
  574.   {
  575.     NameFromLock(g, name, 300);
  576.     fd->fd_SaveDirL = ParentDir(g);
  577.     UnLock(g);
  578.  
  579.     DeleteFile(name);
  580.   }
  581.   else
  582.     return -1;
  583.  
  584.   return fd->fd_SaveDirL;
  585. }
  586.  
  587. /* Open a new subdirectory for SAVE option */
  588. ULONG OpenNewDir(struct FileData *fd, STRPTR name)
  589. {
  590.   ULONG g;
  591.  
  592.   if(fd->fd_SaveDirL)
  593.   {
  594.     g = CurrentDir(fd->fd_SaveDirL);
  595.     if(!(fd->fd_SaveDirL = Lock(name, SHARED_LOCK)))
  596.       if((fd->fd_SaveDirL = CreateDir(name)))
  597.         ChangeMode(CHANGE_LOCK, fd->fd_SaveDirL, SHARED_LOCK);
  598.     UnLock(CurrentDir(g));
  599.   }
  600.   else
  601.     return -1;
  602.  
  603.   return fd->fd_SaveDirL;
  604. }
  605.  
  606. void DoMount(ULONG deep, ULONG hd)
  607. {
  608.   ULONG fh;
  609.   UBYTE buf[50], buf2[60];
  610.  
  611.   sprintf(buf, "T:CheckMountList_%08lx_%03ld", FindTask(0), deep);
  612.  
  613.   if((fh = Open(buf, MODE_NEWFILE)))
  614.   {
  615.     FPrintf(fh,
  616.     "R%lc%ld:\n"
  617.     "\tDevice\t\t= ramdrive.device\n"
  618.     "\tUnit\t\t= %3ld\n"
  619.     "\tSurfaces\t=   2\n"
  620.     "\tBlocksPerTrack\t=  %ld\n"
  621.     "\tReserved\t=   2\n"
  622.     "\tInterleave\t=   0\n"
  623.     "\tLowCyl\t\t=   0\n"
  624.     "\tHighCyl\t\t=  79\n"
  625.     "\tBootPri\t\t= -10\n"
  626.     "\tBuffers\t\t=   5\n"
  627.     "\tBufMemType\t=   1\n#\n", hd ? 'H' : 'D', deep, (hd ? 50 : 10) + deep,
  628.     hd ? 22 : 11);
  629.     Close(fh);
  630.  
  631.     sprintf(buf2, "Mount R%lc%ld: FROM %s", hd ? 'H' : 'D', deep, buf);
  632.     /* I could do this myself, but I don't know, if it is the correct
  633.        method, so I use Mount command. */
  634.     CallSystem(buf2);
  635.     DeleteFile(buf);
  636.   }
  637. }
  638.  
  639. /* Try to get RDx: disk and initialize it. */
  640. BPTR GetRad(struct FileData *fd, STRPTR rname)
  641. {
  642.   UBYTE name[20];
  643.   sprintf(name, NAME "%03ld", fd->fd_ArchiveDepth);
  644.  
  645.   if(Inhibit(rname, 1))
  646.   {
  647.     Format(rname, name, ID_DOS_DISK);
  648.     Inhibit(rname, 0);
  649.     return Lock(rname, SHARED_LOCK);
  650.   }
  651.   else
  652.   {
  653.     LONG i, m = 0;
  654.     UBYTE name2[20];
  655.     struct DosList *dosl;
  656.     if((dosl = LockDosList(LDF_DEVICES|LDF_READ)))
  657.     {
  658.       i = strlen(rname);
  659.       name2[--i] = 0;
  660.       while(i--)
  661.         name2[i] = rname[i];
  662.       dosl = FindDosEntry(dosl, name2, LDF_DEVICES);
  663.       UnLockDosList(LDF_DEVICES|LDF_READ);
  664.       if(!dosl && (fd->fd_Flags & XFDCHECKFLAG_AUTOMOUNT))
  665.       {
  666.     DoMount(fd->fd_ArchiveDepth, fd->fd_Flags &
  667.     XFDCHECKFLAG_HIGHDENSITY);
  668.         m = 1;
  669.       }
  670.       if(dosl || m)
  671.       {
  672.         for(i = 0; i < 50; ++i)
  673.         {
  674.           if(Inhibit(rname, 1))
  675.           {
  676.             Format(rname, name, ID_DOS_DISK);
  677.             Inhibit(rname, 0);
  678.             return Lock(rname, SHARED_LOCK);
  679.           }
  680.           Delay(10);
  681.         }
  682.         /* clear flag if mount failed */
  683.         if(m)
  684.           fd->fd_Flags &= ~XFDCHECKFLAG_AUTOMOUNT;
  685.       }
  686.     }
  687.   }
  688.  
  689.   return 0;
  690. }
  691.  
  692. LONG DoGetVirus(struct FileData *fd, APTR buffer, ULONG buflength)
  693. {
  694.   if(fd->fd_Flags & XFDCHECKFLAG_XVSLIB)
  695.   {
  696.     APTR mem;
  697.       
  698.     if((mem = AllocMem(buflength, MEMF_ANY)))
  699.     {
  700.       struct xvsFileInfo *fi;
  701.       if((fi = (struct xvsFileInfo *) xvsAllocObject(XVSOBJ_FILEINFO)))
  702.       {
  703.         ULONG i;
  704.     /* xvs may modify the buffer! */
  705.         CopyMem(buffer, mem, buflength);
  706.         fi->xvsfi_File = mem;
  707.         fi->xvsfi_FileLen = buflength;
  708.         i = xvsCheckFile(fi);
  709.         if(i == XVSFT_DATAVIRUS)
  710.         {
  711.        PrintXFDTxt(fd, "Data-Virus '%s'", fi->xvsfi_Name);
  712.        ++fd->fd_NumVirus;
  713.      }
  714.         else if(i == XVSFT_FILEVIRUS)
  715.         {
  716.        PrintXFDTxt(fd, "File-Virus '%s'", fi->xvsfi_Name);
  717.        ++fd->fd_NumVirus;
  718.      }
  719.         else if(i == XVSFT_LINKVIRUS)
  720.         {
  721.        PrintXFDTxt(fd, "Link-Virus '%s'", fi->xvsfi_Name);
  722.        ++fd->fd_NumVirus;
  723.      }
  724.         xvsFreeObject(fi);
  725.       }
  726.       else
  727.         PrintXFDErr(fd, XFDCERR_NOVIRUS);
  728.       FreeMem(mem, buflength);
  729.     }
  730.     else
  731.       PrintXFDErr(fd, XFDCERR_NOVIRUS);
  732.   }
  733.  
  734.   return DoFileUnArchive(fd, buffer, buflength);
  735. }
  736.  
  737. /* Call command with NIL: input and output. */
  738. LONG CallSystem(STRPTR com)
  739. {
  740.   ULONG infh;
  741.   LONG err = XFDCERR_RESOURCE;
  742.  
  743.   if((infh = Open("NIL:", MODE_OLDFILE)))
  744.   {
  745.     ULONG outfh;
  746.     if((outfh = Open("NIL:", MODE_NEWFILE)))
  747.     {
  748.       ULONG i;
  749.  
  750.       if(!(i = SystemTags(com, SYS_Input, infh, SYS_Output, outfh, TAG_DONE)))
  751.         err = 0;
  752.       Close(outfh);
  753.     }
  754.     Close(infh);
  755.   }
  756.  
  757.   return err;
  758. }
  759.  
  760. /****************************************************************************/
  761. /****        old Archive stuff, should become obsolete        *****/
  762. /****************************************************************************/
  763.  
  764. #define ARCTYPE_LHA      1
  765. #define ARCTYPE_ZIP      2
  766. #define ARCTYPE_ZOO      3
  767. #define ARCTYPE_LHA_SFX      4
  768. #define ARCTYPE_ARC      5
  769.  
  770. #define XFDCHECKFLAG_ARCCOPY        (1<<27)
  771. #define XFDCHECKFLAG_DIRCHANGE        (1<<28)
  772.  
  773. LONG DoArcNameCheck(struct UnArcData *, STRPTR, ULONG, ULONG,
  774.      struct FileData *);
  775. LONG DeleteAll(STRPTR);
  776.  
  777. struct UnArcData { /* This is allocated to save stack space */
  778.   STRPTR uad_ArcName;
  779.   UBYTE  uad_DestDir[30];
  780.   UBYTE  uad_DoDestDir[30];
  781.   UBYTE  uad_CopyArcName[30];
  782.   UBYTE  uad_Command[200];
  783. };
  784.  
  785. /* types greater than 100 are disk archives */
  786. #define ARCTYPE_ZOOM    101
  787.  
  788. /* Test if we need to copy the archive to a temporary file. This is
  789.    necessary, because most archivers are not able to handle archives
  790.    correctly, when there are pattern characters in the path or archive
  791.    name. Also they fail, when the archive name has an incorrect extension.
  792.  
  793.    For Archivers like Zoo and Arc, which dearchive always to current
  794.    directory, we need to copy always, as the arcname must have an absolute
  795.    path, which is not guarranteed for argument path name, as this may be
  796.    relative to current directory.
  797.    --> except we are already in a decrunched archive, as here the name is
  798.    garanted to be absolute, e.g. start with ':'.
  799.      
  800.    Archives which are crunched with an alien cruncher or are linked must be
  801.    copied as well. (If this really exists ???)
  802.  
  803.    In these cases the archive file is copied with a correct filename and
  804.    extension, so the archiver works well.
  805.    Problem: This needs mem (or disk space when T: is assigned to hard
  806.    disk).
  807. */
  808. LONG DoArcNameCheck(struct UnArcData *uad, STRPTR mem, ULONG buflength,
  809. ULONG arc, struct FileData *fd)
  810. {
  811.   STRPTR p;
  812.   LONG err = 0;
  813.  
  814.   for(p = uad->uad_ArcName; *p; ++p)
  815.   {
  816.     if(*p == '#' || *p == '(' || *p == ')' || *p == '[' || *p == ']'
  817.     || *p == '*' || *p == '~' || *p == '#' || *p == '?' || *p == '|')
  818.       fd->fd_Flags |= XFDCHECKFLAG_ARCCOPY;
  819.   }
  820.   if((fd->fd_Flags & (XFDCHECKFLAG_CRUNCHED|XFDCHECKFLAG_LINKED)) ||
  821.   ((fd->fd_Flags & XFDCHECKFLAG_DIRCHANGE) && !fd->fd_ArchiveDepth))
  822.     fd->fd_Flags |= XFDCHECKFLAG_ARCCOPY;
  823.   else if(!(fd->fd_Flags & XFDCHECKFLAG_ARCCOPY))
  824.   {
  825.     if((p -= 4) <= uad->uad_ArcName) /* position of extension */
  826.       p = uad->uad_ArcName+1; /* at least one char as name is needed */
  827.     switch(arc)
  828.     {
  829.     case ARCTYPE_LHA:
  830.       if(stricmp(p, ".lha") && stricmp(p, ".lzh"))
  831.         fd->fd_Flags |= XFDCHECKFLAG_ARCCOPY;
  832.       break;
  833.     case ARCTYPE_ZIP:
  834.       if(stricmp(p, ".zip")) fd->fd_Flags |= XFDCHECKFLAG_ARCCOPY;
  835.       break;
  836.     case ARCTYPE_LHA_SFX:
  837.       if(stricmp(p, ".run")) fd->fd_Flags |= XFDCHECKFLAG_ARCCOPY;
  838.       break;
  839.     case ARCTYPE_ARC:
  840.       if(stricmp(p, ".arc")) fd->fd_Flags |= XFDCHECKFLAG_ARCCOPY;
  841.       break;
  842.     case ARCTYPE_ZOO:
  843.       if(stricmp(p, ".zoo")) fd->fd_Flags |= XFDCHECKFLAG_ARCCOPY;
  844.       break;
  845.     }            
  846.   }
  847.   if(fd->fd_Flags & XFDCHECKFLAG_ARCCOPY)
  848.   {
  849.     ULONG d;
  850.     switch(arc)
  851.     {
  852.     case ARCTYPE_LHA:
  853.       p = ".lha"; break;
  854.     case ARCTYPE_ZIP:
  855.       p = ".zip"; break;
  856.     case ARCTYPE_ZOO:
  857.       p = ".zoo"; break;
  858.     case ARCTYPE_LHA_SFX:
  859.       p = ".run"; break;
  860.     case ARCTYPE_ARC:
  861.       p = ".arc"; break;
  862.     case ARCTYPE_ZOOM:
  863.       p = ".zom"; break;
  864.     }            
  865.     sprintf(uad->uad_CopyArcName, "T:CheckArc_%08lx_%03ld%s", FindTask(0),
  866.     fd->fd_ArchiveDepth, p);
  867.     uad->uad_ArcName = uad->uad_CopyArcName;
  868.     if((d = Open(uad->uad_ArcName, MODE_NEWFILE)))
  869.     {
  870.       if(Write(d, mem, buflength) != buflength)
  871.         err = XFDCERR_READWRITE;
  872.       Close(d);
  873.     }
  874.     else
  875.       err = XFDCERR_OPENERR;
  876.   }
  877.  
  878.   return err;
  879. }
  880.  
  881. /* Tests if a file is an archive. When yes, the archive is unarchived and
  882.    DoDirectoryScan is called for the result files. Else DoFileUnLink is
  883.    called.
  884. */
  885. LONG DoFileUnArchiveOld(struct FileData *fd, APTR buffer, ULONG buflength)
  886. {
  887.   ULONG arc = 0;
  888.   STRPTR mem = (STRPTR) buffer;
  889.   LONG err = 0;
  890.  
  891.   if(buflength > 7 && mem[2] == '-' && mem[3] == 'l' && mem[4] == 'h'
  892.   && mem[6] == '-')
  893.   { /* This is an LhA-File */
  894.     arc = ARCTYPE_LHA;
  895.     PrintXFDTxt(fd, "LhA (ARCHIVE)");
  896.   }
  897.   else if(buflength > 4 && mem[0] == 'P' && mem[1] == 'K' && mem[2] == 3
  898.   && mem[3] == 4)
  899.   {
  900.     arc = ARCTYPE_ZIP;
  901.     PrintXFDTxt(fd, "Zip (ARCHIVE)");
  902.   }
  903.   else if(buflength > 4 && mem[0] == 'Z' && mem[1] == 'O' && mem[2] == 'O'
  904.   && mem[3] == ' ' && mem[5] == '.')
  905.   {
  906.     arc = ARCTYPE_ZOO;
  907.     fd->fd_Flags |= XFDCHECKFLAG_DIRCHANGE;
  908.     PrintXFDTxt(fd, "ZOO (ARCHIVE)");
  909.   }
  910.   else if(buflength > 4 && mem[0x2C] == 'S' && mem[0x2D] == 'F' &&
  911.   mem[0x2E] == 'X' && mem[0x2F] == '!' && *((ULONG *)mem) == 0x3F3)
  912.   {
  913.     arc = ARCTYPE_LHA_SFX;
  914.     PrintXFDTxt(fd, "LhA SFX (ARCHIVE)");
  915.   }
  916.   else if(buflength > 2 && mem[0] == 0x1A && mem[1] && mem[1] < 9)
  917.   { /* This detection is very unsecure !!! */
  918.     arc = ARCTYPE_ARC;
  919.     fd->fd_Flags |= XFDCHECKFLAG_DIRCHANGE;
  920.     PrintXFDTxt(fd, "Arc (ARCHIVE)");
  921.   }
  922.   else if(buflength > 4 && mem[0] == 'Z' && mem[1] == 'O' && mem[2] == 'M'
  923.   && mem[3] == '5')
  924.   {
  925.     arc = ARCTYPE_ZOOM;
  926.     PrintXFDTxt(fd, "Zoom (ARCHIVE)");
  927.   }
  928.  
  929.   if(arc)
  930.   {
  931.     if((arc < 100 && !(fd->fd_Flags & XFDCHECKFLAG_NOUNARCHIVE)) ||
  932.     (arc >= 100 && !(fd->fd_Flags & XFDCHECKFLAG_NOUNTRACK)))
  933.     {
  934.       struct UnArcData *uad;
  935.  
  936.       if((uad = (struct UnArcData *) AllocMem(sizeof(struct UnArcData),
  937.       MEMF_ANY)))
  938.       { /* AllocMem to prevent stack overflow */
  939.  
  940.     uad->uad_ArcName = fd->fd_Name;
  941.     err = DoArcNameCheck(uad, mem, buflength, arc, fd);
  942.  
  943.         FreeCrunchMemList(fd, mem);
  944.         if(!err && !OpenNewDir(fd, FilePart(fd->fd_Name)))
  945.       err = XFDCERR_OPENERR;
  946.         if(!err)
  947.         {
  948.           ULONG destdir, storedir = 0;
  949.  
  950.       if(arc > 100)
  951.       {
  952.             sprintf(uad->uad_DestDir, "RD%ld:", fd->fd_DDDepth);
  953.             strcpy(uad->uad_DoDestDir, uad->uad_DestDir);
  954.  
  955.             if((destdir = GetRad(fd, uad->uad_DestDir)))
  956.             {
  957.           UnLock(destdir);
  958.           sprintf(uad->uad_Command, "ZOOM NOPROMPT FROM \"%s\" TO %s",
  959.           uad->uad_ArcName, uad->uad_DestDir);
  960.  
  961.               err = CallSystem(uad->uad_Command);
  962.  
  963.           if(!(destdir = Lock(uad->uad_DestDir, SHARED_LOCK)) && !err)
  964.                 err = XFDCERR_NODOS;
  965.             }
  966.         else
  967.           err = XFDCERR_NORAD;
  968.       }
  969.       else
  970.       {
  971.             sprintf(uad->uad_DestDir, "T:CheckX_%08lx_%03ld",
  972.             FindTask(0), fd->fd_ArchiveDepth);
  973.             sprintf(uad->uad_DoDestDir, "T:CheckX_%08lx_%03ld/#?",
  974.             FindTask(0), fd->fd_ArchiveDepth);
  975.  
  976.         if((destdir = CreateDir(uad->uad_DestDir)))
  977.         {
  978.           ChangeMode(CHANGE_LOCK, destdir, SHARED_LOCK);
  979.           if(fd->fd_Flags & XFDCHECKFLAG_DIRCHANGE)
  980.                 storedir = CurrentDir(destdir);
  981.  
  982.               switch(arc)
  983.           {
  984.           case ARCTYPE_LHA: case ARCTYPE_LHA_SFX:
  985.             sprintf(uad->uad_Command, "Lha -IMmq x \"%s\" %s/",
  986.             uad->uad_ArcName, uad->uad_DestDir);
  987.             break;
  988.           case ARCTYPE_ZIP:
  989.             sprintf(uad->uad_Command, "UnZip \"%s\" -d %s/",
  990.             uad->uad_ArcName, uad->uad_DestDir);
  991.             break;
  992.           case ARCTYPE_ZOO:
  993.             sprintf(uad->uad_Command, "Zoo x//qqq \"%s\"",
  994.             uad->uad_ArcName);
  995.             break;
  996.           case ARCTYPE_ARC:
  997.             sprintf(uad->uad_Command, "Arc xwn \"%s\"",
  998.             uad->uad_ArcName);
  999.             break;
  1000.           }
  1001.  
  1002.               err = CallSystem(uad->uad_Command);
  1003.             }
  1004.         else
  1005.           err = XFDCERR_OPENDIR;
  1006.           }
  1007.         if(fd->fd_Flags & XFDCHECKFLAG_ARCCOPY)
  1008.         { /* save some memory */
  1009.         fd->fd_Flags &= ~XFDCHECKFLAG_ARCCOPY;
  1010.         DeleteFile(uad->uad_ArcName);
  1011.       }
  1012.       if(destdir)
  1013.       {
  1014.         if(!err)
  1015.         {
  1016.           struct FileData fdp;
  1017.  
  1018.           CopyMem(fd, &fdp, sizeof(struct FileData));
  1019.           fdp.fd_Flags = (fdp.fd_Flags&XFDCALLFLAGS)|XFDCHECKFLAG_ALL;
  1020.           ++fdp.fd_ArchiveDepth;
  1021.           ++fdp.fd_RecurseDepth;
  1022.           fdp.fd_MemList = 0;
  1023.  
  1024.           if(arc > 100)
  1025.                 ++fdp.fd_DDDepth;
  1026.  
  1027.           err = DoDirectoryScan(uad->uad_DoDestDir, 0, &fdp);
  1028.           fd->fd_SaveDirL = fdp.fd_SaveDirL;
  1029.           fd->fd_NumVirus = fdp.fd_NumVirus;
  1030.         }
  1031.  
  1032.         if(fd->fd_Flags & XFDCHECKFLAG_DIRCHANGE)
  1033.           CurrentDir(storedir);
  1034.         UnLock(destdir);
  1035.         if(arc < 100)
  1036.           DeleteAll(uad->uad_DestDir);
  1037.       }
  1038.  
  1039.           if(!OpenParentDir(fd))
  1040.         err = XFDCERR_OPENDIR;
  1041.         }
  1042.       if(fd->fd_Flags & XFDCHECKFLAG_ARCCOPY)
  1043.       DeleteFile(uad->uad_ArcName);
  1044.  
  1045.         FreeMem(uad, sizeof(struct UnArcData));
  1046.       }
  1047.       else
  1048.         err = XFDCERR_NOMEMORY;
  1049.     }
  1050.   }
  1051.   else
  1052.     err = DoFileUnLink(fd, buffer, buflength);
  1053.  
  1054.   return err;
  1055. }
  1056.  
  1057. /* This deletes a temporary directory and all files in it.
  1058.    It returns 0 on error and gets name of directory to delete.
  1059. */
  1060. LONG DeleteAll(STRPTR name)
  1061. {
  1062.   LONG retval;
  1063.   struct AnchorPath *APath;
  1064.   STRPTR fname;
  1065.  
  1066.   if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath) +
  1067.   512, MEMF_PUBLIC|MEMF_CLEAR)))
  1068.   {
  1069.     APath->ap_Strlen = 256;
  1070.  
  1071.     fname = (STRPTR) APath->ap_Buf + 256;
  1072.     for(retval = MatchFirst(name, APath); !retval; retval = MatchNext(APath))
  1073.     {
  1074.       if(*fname)
  1075.       {
  1076.         SetProtection(fname, 0); /* set RWED bits */
  1077.         DeleteFile(fname);
  1078.       }
  1079.  
  1080.       CopyMem(APath->ap_Buf, fname, 256);
  1081.  
  1082.       if(APath->ap_Flags & APF_DIDDIR)
  1083.         APath->ap_Flags &= ~APF_DIDDIR; /* clear flag */
  1084.       else if(APath->ap_Info.fib_DirEntryType > 0) /* a directory */
  1085.       {
  1086.         APath->ap_Flags |= APF_DODIR; *fname = 0;
  1087.       }
  1088.     }
  1089.     MatchEnd(APath);
  1090.  
  1091.     FreeMem(APath, sizeof(struct AnchorPath) + 512);
  1092.   }
  1093.  
  1094.   return DeleteFile(name); /* when this returns error, then any of the
  1095.   above functions may have failed --> directory not empty. */
  1096. }
  1097.  
  1098. /****************************************************************************/
  1099.  
  1100. /* Tests if a file is an archive. When yes, the archive is unarchived and
  1101.    DoDirectoryScan is called for the result files. Else DoFileUnLink is
  1102.    called.
  1103. */
  1104. LONG DoFileUnArchive(struct FileData *fd, APTR buffer, ULONG buflength)
  1105. {
  1106.   LONG err = 0;
  1107.  
  1108.   if(fd->fd_Flags & XFDCHECKFLAG_XADLIB)
  1109.   {
  1110.     struct xadArchiveInfo *ai;
  1111.  
  1112.     if((ai = (struct xadArchiveInfo *) xadAllocObject(XADOBJ_ARCHIVEINFO, 0)))
  1113.     {
  1114.       if(!xadGetInfo(ai, XAD_INMEMORY, buffer, XAD_INSIZE, buflength,
  1115.       TAG_DONE))
  1116.       {
  1117.     STRPTR arcname;
  1118.     
  1119.     arcname = fd->fd_Name;
  1120.  
  1121.         if(ai->xai_Flags & XADAIF_FILECORRUPT)
  1122.           PrintXFDTxt(fd, "%s (ARCHIVE, CORRUPTED)", ai->xai_Client->xc_ArchiverName);
  1123.         else
  1124.           PrintXFDTxt(fd, "%s (ARCHIVE)", ai->xai_Client->xc_ArchiverName);
  1125.         
  1126.         if(!(!(fd->fd_Flags & XFDCHECKFLAG_NOUNARCHIVE) && ai->xai_FileInfo ||
  1127.         !(fd->fd_Flags & XFDCHECKFLAG_NOUNTRACK) && ai->xai_DiskInfo))
  1128.           err = DoFileUnArchiveOld(fd, buffer, buflength); /* later DoFileUnLink */
  1129.         else if(!OpenNewDir(fd, FilePart(fd->fd_Name)))
  1130.       err = XFDCERR_OPENERR;
  1131.     else
  1132.     {
  1133.       if(!(fd->fd_Flags & XFDCHECKFLAG_NOUNARCHIVE) && ai->xai_FileInfo)
  1134.       {
  1135.         struct xadFileInfo *fi;
  1136.         fi = ai->xai_FileInfo;
  1137.         while(!CTRL_C && fi)
  1138.         {
  1139.           APTR dest;
  1140.           
  1141.           if(!(fi->xfi_Flags & (XADFIF_DIRECTORY|XADFIF_LINK)))
  1142.           {
  1143.                 ULONG flags;
  1144.  
  1145.                 flags = fd->fd_Flags;
  1146.                 fd->fd_Flags &= ~XFDCHECKFLAG_NAMEPRINTED;
  1147.                 fd->fd_Name = fi->xfi_FileName;
  1148.                 fd->fd_RecurseDepth++;
  1149.                 fd->fd_ArchiveDepth++;
  1150.             if((dest = AllocMem(fi->xfi_Size, MEMF_PUBLIC)))
  1151.             {
  1152.               if(!(err = AddCrunchMemList(fd, dest, fi->xfi_Size)))
  1153.               {
  1154.                     if((err = xadFileUnArc(ai, XAD_OUTMEMORY, dest, XAD_OUTSIZE,
  1155.                     fi->xfi_Size, XAD_ENTRYNUMBER, fi->xfi_EntryNumber, TAG_DONE)))
  1156.                       err += XADERR_OFFSET;
  1157.                     else
  1158.                     {
  1159.                       if((fd->fd_Flags & XFDCHECKFLAG_PRINTALL) ||
  1160.                       ((fd->fd_Flags & XFDCHECKFLAG_PRINTEXEC) && fi->xfi_Size > 4
  1161.                       && *((ULONG *)dest) == HUNK_HEADER))
  1162.                         PrintXFDFile(fd);
  1163.                       err = DoGetVirus(fd, dest, fi->xfi_Size);
  1164.                     }
  1165.                     FreeCrunchMemList(fd, dest);
  1166.                   }
  1167.                   else
  1168.                     FreeMem(dest, fi->xfi_Size);
  1169.             }
  1170.             else
  1171.               err = XFDCERR_NOMEMORY;
  1172.  
  1173.             if(err)
  1174.             {
  1175.               PrintXFDErr(fd, err);
  1176.               err = 0;
  1177.             }
  1178.                 --fd->fd_RecurseDepth;
  1179.                 --fd->fd_ArchiveDepth;
  1180.                 fd->fd_Flags = flags;
  1181.           }
  1182.           fi = fi->xfi_Next;
  1183.         }
  1184.       }
  1185.       if(!(fd->fd_Flags & XFDCHECKFLAG_NOUNTRACK) && ai->xai_DiskInfo)
  1186.       {
  1187.         struct DiskInfoData {
  1188.           UBYTE name[10];
  1189.           UBYTE buf[50];
  1190.           BPTR destdir;
  1191.           ULONG geom;
  1192.         } *d;
  1193.  
  1194.         /* reduce stacksize, as we have a recursive program */
  1195.         if((d = AllocMem(sizeof(struct DiskInfoData), MEMF_PUBLIC)))
  1196.         {
  1197.           struct xadDiskInfo *di;
  1198.           di = ai->xai_DiskInfo;
  1199.  
  1200.           while(!CTRL_C && di)
  1201.           {
  1202.             if(di->xdi_SectorSize != 512 || di->xdi_Heads != 2 ||
  1203.             di->xdi_Cylinders != 80 || (di->xdi_TrackSectors != 11 &&
  1204.             di->xdi_TrackSectors != 22))
  1205.             {
  1206.               sprintf(d->buf, "-disk image %ld (unsupported geometry)", di->xdi_EntryNumber);
  1207.               d->geom = 1;
  1208.             }
  1209.             else
  1210.             {
  1211.               d->geom = 0;
  1212.               if(di->xdi_TrackSectors == 11)
  1213.                     sprintf(d->name, "RD%ld:", fd->fd_DDDepth);
  1214.               else
  1215.               {
  1216.                 fd->fd_Flags |= XFDCHECKFLAG_HIGHDENSITY;
  1217.                     sprintf(d->name, "RH%ld:", fd->fd_HDDepth);
  1218.                   }
  1219.  
  1220.           if(di->xdi_LowCyl || di->xdi_HighCyl != 79)
  1221.                 sprintf(d->buf, "-disk image %ld (%s, %ld to %ld)",
  1222.                 di->xdi_EntryNumber, fd->fd_Flags & XFDCHECKFLAG_HIGHDENSITY ?
  1223.                 "HD" : "DD", di->xdi_LowCyl, di->xdi_HighCyl);
  1224.               else
  1225.                 sprintf(d->buf, "-disk image %ld (%s)",
  1226.                 di->xdi_EntryNumber, fd->fd_Flags & XFDCHECKFLAG_HIGHDENSITY ?
  1227.                 "HD" : "DD");
  1228.             }
  1229.           
  1230.             fd->fd_Name = d->buf;
  1231.                 PrintXFDFile(fd);
  1232.  
  1233.             if(di->xdi_TextInfo)
  1234.             {
  1235.               struct xadTextInfo *ti;
  1236.               ULONG flags, i = 1;
  1237.  
  1238.           for(ti = di->xdi_TextInfo; ti; ti = ti->xti_Next)
  1239.           {
  1240.             if(ti->xti_Size && ti->xti_Text)
  1241.             {
  1242.                       flags = fd->fd_Flags;
  1243.                       fd->fd_Flags &= ~XFDCHECKFLAG_NAMEPRINTED;
  1244.                       fd->fd_Flags |= XFDCHECKFLAG_NOFREEMEM;
  1245.                       fd->fd_RecurseDepth++;
  1246.                       sprintf(d->buf, "--infotext %ld (size %ld)", i, ti->xti_Size);
  1247.                       if((fd->fd_Flags & XFDCHECKFLAG_PRINTALL) ||
  1248.                       ((fd->fd_Flags & XFDCHECKFLAG_PRINTEXEC) && ti->xti_Size > 4
  1249.                       && *((ULONG *)(ti->xti_Text)) == HUNK_HEADER))
  1250.                         PrintXFDFile(fd);
  1251.                       PrintXFDErr(fd, DoGetVirus(fd, ti->xti_Text, ti->xti_Size));
  1252.                       --fd->fd_RecurseDepth;
  1253.                       fd->fd_Flags = flags;
  1254.                     }
  1255.                     ++i;
  1256.                   }
  1257.             }
  1258.  
  1259.             if(!d->geom)
  1260.             {
  1261.               if((di->xdi_LowCyl == 0 && di->xdi_HighCyl == 79) ||
  1262.               !(fd->fd_Flags & XFDCHECKFLAG_NOTRACKCUT))
  1263.           {
  1264.                     if((d->destdir = GetRad(fd, d->name)))
  1265.                     {
  1266.               struct xadDeviceInfo *dvi;
  1267.  
  1268.                   UnLock(d->destdir);
  1269.  
  1270.                   if((dvi = (struct xadDeviceInfo *)
  1271.                   xadAllocObjectA(XADOBJ_DEVICEINFO, 0)))
  1272.                   {
  1273.                     d->name[strlen(d->name)-1] = 0;
  1274.                     dvi->xdi_DOSName = d->name;
  1275.                 err = xadDiskUnArc(ai, XAD_OUTDEVICE, dvi,
  1276.                 XAD_ENTRYNUMBER, di->xdi_EntryNumber, XAD_VERIFY,
  1277.                 TRUE, TAG_DONE);
  1278.                     xadFreeObjectA(dvi, 0);
  1279.                     d->name[strlen(d->name)] = ':';
  1280.                   }
  1281.                   else
  1282.                     err = XFDCERR_NOMEMORY;
  1283.  
  1284.               if(err)
  1285.               {
  1286.                 PrintXFDErr(fd, XADERR_OFFSET+err); err = 0;
  1287.               }
  1288.               else if(!(d->destdir = Lock(d->name, SHARED_LOCK)))
  1289.                         PrintXFDErr(fd, XFDCERR_NODOS);
  1290.                       else
  1291.                       {
  1292.                     struct FileData fdp;
  1293.  
  1294.                     CopyMem(fd, &fdp, sizeof(struct FileData));
  1295.                     fdp.fd_Flags = (fdp.fd_Flags&XFDCALLFLAGS)|XFDCHECKFLAG_ALL;
  1296.                     fdp.fd_MemList = 0;
  1297.                 fdp.fd_ArchiveDepth++;
  1298.                 fdp.fd_RecurseDepth++;
  1299.                     if(fd->fd_Flags & XFDCHECKFLAG_HIGHDENSITY)
  1300.                       ++fdp.fd_HDDepth;
  1301.                     else
  1302.                       ++fdp.fd_DDDepth;
  1303.  
  1304.                       PrintXFDErr(fd, DoDirectoryScan(d->name, 0, &fdp));
  1305.                       fd->fd_SaveDirL = fdp.fd_SaveDirL;
  1306.                       fd->fd_NumVirus = fdp.fd_NumVirus;
  1307.                       UnLock(d->destdir);
  1308.                       }
  1309.                     }
  1310.                     else
  1311.                       PrintXFDErr(fd, XFDCERR_NORAD);
  1312.               }
  1313.             }
  1314.             di = di->xdi_Next;
  1315.           } /* while */
  1316.           FreeMem(d, sizeof(struct DiskInfoData));
  1317.         } /* AllocMem DiskInfoData */
  1318.         else
  1319.           err = XFDCERR_NOMEMORY;
  1320.       } /* is there is disk entry? */
  1321.           if(!OpenParentDir(fd))
  1322.             err = XFDCERR_OPENDIR;
  1323.     }
  1324.     
  1325.     fd->fd_Name = arcname;
  1326.       }
  1327.       else
  1328.         err = DoFileUnArchiveOld(fd, buffer, buflength); /* later DoFileUnLink */
  1329.  
  1330.       xadFreeObjectA(ai, 0);
  1331.     }
  1332.     else
  1333.       err = XFDCERR_NOMEMORY;
  1334.   }
  1335.   else
  1336.     err = DoFileUnArchiveOld(fd, buffer, buflength); /* later DoFileUnLink */
  1337.  
  1338.   return err;
  1339. }
  1340.  
  1341. /* Tries to unlink a file. When the file was linked, we call DoGetVirus
  1342.    for the two parts to check if they may be archives, else we call
  1343.    DoFileUnCrunch.
  1344. */
  1345. LONG DoFileUnLink(struct FileData *fd, APTR buffer, ULONG buflength)
  1346. {
  1347.   LONG ret = XFDCERR_NOMEMORY;
  1348.   struct xfdLinkerInfo *xli;
  1349.  
  1350.   if((xli = (struct xfdLinkerInfo *) xfdAllocObject(XFDOBJ_LINKERINFO)))
  1351.   {
  1352.     xli->xfdli_Buffer = buffer;
  1353.     xli->xfdli_BufLen = buflength;
  1354.     if(xfdRecogLinker(xli))
  1355.     {
  1356.       PrintXFDTxt(fd, xli->xfdli_LinkerName);
  1357.       if(fd->fd_Flags & XFDCHECKFLAG_NOUNLINK)
  1358.         ret = DoFileUnCrunch(fd, buffer, buflength);
  1359.       else if(xfdUnlink(xli))
  1360.       {
  1361.         ULONG flags;
  1362.     fd->fd_Flags |= XFDCHECKFLAG_LINKED;
  1363.         ++fd->fd_RecurseDepth;
  1364.         ++fd->fd_LinkNum;
  1365.     flags = fd->fd_Flags;
  1366.     fd->fd_Flags |= XFDCHECKFLAG_NOFREEMEM;
  1367.         PrintXFDErr(fd, DoGetVirus(fd, xli->xfdli_Save1,
  1368.         xli->xfdli_SaveLen1));
  1369.         fd->fd_Flags = flags; /* XFDCHECKFLAG_NOFREEMEM is cleared */
  1370.         PrintXFDErr(fd, DoGetVirus(fd, xli->xfdli_Save2,
  1371.         xli->xfdli_SaveLen2));
  1372.         ret = 0;
  1373.         --fd->fd_RecurseDepth;
  1374.       }
  1375.       else
  1376.         ret = XFDERR_OFFSET + xli->xfdli_Error;
  1377.     }
  1378.     else
  1379.       ret = DoFileUnCrunch(fd, buffer, buflength);
  1380.  
  1381.     xfdFreeObject(xli);
  1382.   }
  1383.   return ret;
  1384. }
  1385.  
  1386. /* Tries to decrunch a file. When it is crunched, we decrunch it and call
  1387.    DoGetVirus to start the loop again. Else we call unstripping.
  1388. */
  1389. LONG DoFileUnCrunch(struct FileData *fd, APTR buffer, ULONG buflength)
  1390. {
  1391.   LONG ret = XFDCERR_NOMEMORY;
  1392.   struct xfdBufferInfo *xbi;
  1393.  
  1394.   if((xbi = (struct xfdBufferInfo *) xfdAllocObject(XFDOBJ_BUFFERINFO)))
  1395.   {
  1396.     xbi->xfdbi_SourceBuffer = buffer;
  1397.     xbi->xfdbi_SourceBufLen = buflength;
  1398.     xbi->xfdbi_Flags = XFDFF_RECOGEXTERN;
  1399.     if(xfdRecogBuffer(xbi))
  1400.     {
  1401.       struct Library *xpkbase;
  1402.       STRPTR buf = 0;
  1403.       ULONG buflen = 0;
  1404.  
  1405.       PrintXFDTxt(fd, xbi->xfdbi_PackerFlags & XFDPFF_ADDR ? "%s (ADDRESS)" :
  1406.       "%s", xbi->xfdbi_PackerName);
  1407.  
  1408.       if(fd->fd_Flags & XFDCHECKFLAG_ASKPWD && (xpkbase =
  1409.       OpenLibrary(XPKNAME, 4)))
  1410.       {
  1411.     ASSIGN_XPK
  1412.         if(xbi->xfdbi_PackerFlags & XFDPFF_PASSWORD)
  1413.         {
  1414.           buflen = (xbi->xfdbi_MaxSpecialLen == 0xFFFF) ? 256 :
  1415.         xbi->xfdbi_MaxSpecialLen;
  1416.           if((buf = (STRPTR) AllocMem(buflen, MEMF_ANY|MEMF_CLEAR)))
  1417.       {
  1418.             if(!XpkPassRequestTags(XPK_PasswordBuf, buf,
  1419.             XPK_PassBufSize, buflen, TAG_DONE))
  1420.           xbi->xfdbi_Special = buf;
  1421.       }
  1422.         }
  1423.         else if(xbi->xfdbi_PackerFlags & XFDPFF_KEY16)
  1424.         {
  1425.       if(!XpkPassRequestTags(XPK_Key16BitPtr, &buflen, TAG_DONE))
  1426.         xbi->xfdbi_Special = &buflen;
  1427.         }
  1428.         else if(xbi->xfdbi_PackerFlags & XFDPFF_KEY32)
  1429.         {
  1430.       if(!XpkPassRequestTags(XPK_Key32BitPtr, &buflen, TAG_DONE))
  1431.             xbi->xfdbi_Special = &buflen;
  1432.         }
  1433.     CloseLibrary(xpkbase);
  1434.       }
  1435.       if(fd->fd_Flags & XFDCHECKFLAG_NODECRUNCH)
  1436.         ret = DoFileStrip(fd, buffer, buflength);
  1437.       else if(xfdDecrunchBuffer(xbi))
  1438.       {
  1439.         if((xbi->xfdbi_PackerFlags & XFDPFF_ADDR) &&
  1440.         !(fd->fd_Flags & XFDCHECKFLAG_ADDRESS))
  1441.         {
  1442.       fd->fd_Flags |= XFDCHECKFLAG_ADDRESS;
  1443.           PrintXFDErr(fd, SaveUncrFile(fd, buffer, buflength));
  1444.         }
  1445.     fd->fd_Flags |= XFDCHECKFLAG_CRUNCHED;
  1446.         FreeCrunchMemList(fd, buffer);
  1447.         ++fd->fd_RecurseDepth;
  1448.         if(!(ret = AddCrunchMemList(fd, xbi->xfdbi_TargetBuffer,
  1449.         xbi->xfdbi_TargetBufLen)))
  1450.         {
  1451.           PrintXFDErr(fd, DoGetVirus(fd, xbi->xfdbi_TargetBuffer,
  1452.             xbi->xfdbi_TargetBufSaveLen));
  1453.         }
  1454.         --fd->fd_RecurseDepth;
  1455.       }
  1456.       else
  1457.         ret = XFDERR_OFFSET + xbi->xfdbi_Error;
  1458.  
  1459.       if(buf)
  1460.         FreeMem(buf, buflen);
  1461.     }
  1462.     else
  1463.       ret = DoFileStrip(fd, buffer, buflength);
  1464.  
  1465.     xfdFreeObject(xbi);
  1466.   }
  1467.   return ret;
  1468. }
  1469.  
  1470. /* Tries to strip useless hunks in a file. When there are some, we remove
  1471.    them and call DoGetVirus to start the loop again. Else we finish.
  1472.    When either unlinking or uncrunching happend in before loops, we may
  1473.    save the file when there was SAVE option.
  1474. */
  1475. LONG DoFileStrip(struct FileData *fd, APTR buffer, ULONG buflength)
  1476. {
  1477.   LONG ret = 0;
  1478.   ULONG reslength = buflength;
  1479.  
  1480.   if(*((ULONG *) buffer) == 0x000003F3 && !(fd->fd_Flags &
  1481.   XFDCHECKFLAG_NOSTRIP))
  1482.     xfdStripHunks(buffer, buflength, &reslength,
  1483.     XFDSHF_NAME|XFDSHF_SYMBOL|XFDSHF_DEBUG);
  1484.     /* errors are not interpreted */
  1485.  
  1486.   if(buflength > reslength)
  1487.   {
  1488.     fd->fd_Flags |= XFDCHECKFLAG_STRIPPED;
  1489.     PrintXFDTxt(fd, "%ld bytes stripped", buflength-reslength);
  1490.     ret = DoGetVirus(fd, buffer, reslength);
  1491.   }
  1492.  
  1493.   if(!ret && !(fd->fd_Flags & XFDCHECKFLAG_ADDRESS))
  1494.     ret = SaveUncrFile(fd, buffer, buflength);
  1495.   FreeCrunchMemList(fd, buffer);
  1496.  
  1497.   return ret;
  1498. }
  1499.  
  1500. /* Print file name */
  1501. void PrintXFDFile(struct FileData *fd)
  1502. {
  1503.   STRPTR name = fd->fd_Name;
  1504.   UBYTE i;
  1505.  
  1506.   if(fd->fd_ArchiveDepth) /* skip that ugly T:CheckX.. or RD?: */
  1507.   {
  1508.     if(*name == 'R' && (name[1] == 'D' || name[1] == 'H'))
  1509.     {
  1510.       while(*name != ':')
  1511.         ++name;
  1512.       ++name;
  1513.     }
  1514.     else if(*name == 'T' && name[1] == ':')    /* becomes obsolete with Archive stuff remove */
  1515.     {
  1516.       while(*name != '/')
  1517.         ++name;
  1518.       ++name;
  1519.     }
  1520.   }
  1521.  
  1522.   if(fd->fd_LogFileFH)
  1523.   {
  1524.     for(i = 0; i < fd->fd_ArchiveDepth; ++i)
  1525.       FPutC(fd->fd_LogFileFH, '*');
  1526.     FPrintf(fd->fd_LogFileFH, "%s\n", name);
  1527.   }
  1528.   for(i = 0; i < fd->fd_ArchiveDepth; ++i)
  1529.     FPutC(Output(), '*');
  1530.   Printf("%s\n", name);
  1531.   fd->fd_Flags |= XFDCHECKFLAG_NAMEPRINTED;
  1532. }
  1533.  
  1534. /* Print Error - Error 100 and up are CheckX special errors. */
  1535. void PrintXFDErr(struct FileData *fd, LONG err)
  1536. {
  1537.   if(err)
  1538.   {
  1539.     STRPTR txt = 0, txt2;
  1540.     UBYTE i;
  1541.  
  1542.     if(err > XFDERR_OFFSET)
  1543.     {
  1544.       txt2 = " XFD-Error %ld: %s\n";
  1545.       err -= XFDERR_OFFSET;
  1546.       txt = xfdGetErrorText(err);
  1547.     }
  1548.     else if(err > XADERR_OFFSET)
  1549.     {
  1550.       txt2 = " XAD-Error %ld: %s\n";
  1551.       err -= XADERR_OFFSET;
  1552.       txt = xadGetErrorText(err);
  1553.     }
  1554.     else
  1555.     {
  1556.       txt2 = " CheckX-Error %ld: %s\n";
  1557.       switch(err)
  1558.       {
  1559.       case XFDCERR_NOMEMORY:    txt = "not enough memory";    break;
  1560.       case XFDCERR_EXAMINEERR:    txt = "examining failed";    break;
  1561.       case XFDCERR_OPENERR:    txt = "opening file failed";    break;
  1562.       case XFDCERR_READWRITE:    txt = "read or write failed";    break;
  1563.       case XFDCERR_SCANERR:    txt = "directory scan failed";    break;
  1564.       case XFDCERR_BREAK:    txt = "user break";        break;
  1565.       case XFDCERR_OPENDIR:    txt = "opening directory failed"; break;
  1566.       case XFDCERR_NORAD:    txt = "accessing ramdrive failed"; break;
  1567.       case XFDCERR_NODOS:    txt = "not a dos disk";        break;
  1568.       case XFDCERR_RESOURCE:    txt = "needed resource not available"; break;
  1569.       case XFDCERR_NOVIRUS:    txt = "could not check for virus"; break;
  1570.       }
  1571.     }
  1572.  
  1573.     if(!(fd->fd_Flags & XFDCHECKFLAG_NAMEPRINTED))
  1574.       PrintXFDFile(fd);
  1575.     if(fd->fd_LogFileFH)
  1576.     {
  1577.       for(i = 0; i < fd->fd_RecurseDepth; ++i)
  1578.         FPutC(fd->fd_LogFileFH, ' ');
  1579.       FPrintf(fd->fd_LogFileFH, txt2, err, txt);
  1580.       Flush(fd->fd_LogFileFH);
  1581.     }
  1582.     for(i = 0; i < fd->fd_RecurseDepth; ++i)
  1583.       FPutC(Output(), ' ');
  1584.     Printf(txt2, err, txt);
  1585.   }
  1586. }
  1587.  
  1588. /* Print type text */
  1589. void PrintXFDTxt(struct FileData *fd, STRPTR txt, ...)
  1590. {
  1591.   UBYTE i;
  1592.  
  1593.   if(!(fd->fd_Flags & XFDCHECKFLAG_NAMEPRINTED))
  1594.     PrintXFDFile(fd);
  1595.   if(fd->fd_LogFileFH)
  1596.   {
  1597.     for(i = 0; i <= fd->fd_RecurseDepth; ++i)
  1598.       FPutC(fd->fd_LogFileFH, ' ');
  1599.     VFPrintf(fd->fd_LogFileFH, txt, &txt+1);
  1600.     FPutC(fd->fd_LogFileFH, '\n');
  1601.     Flush(fd->fd_LogFileFH);
  1602.   }
  1603.   for(i = 0; i <= fd->fd_RecurseDepth; ++i)
  1604.     FPutC(Output(), ' ');
  1605.   VPrintf(txt, &txt+1);
  1606.   FPutC(Output(), '\n');
  1607. }
  1608.  
  1609. /* Add memory to the memory list. */
  1610. LONG AddCrunchMemList(struct FileData *fd, APTR reg, ULONG size)
  1611. {
  1612.   struct CrunchMemList *ml;
  1613.  
  1614.   if((ml = (struct CrunchMemList *) AllocMem(sizeof(struct CrunchMemList),
  1615.   MEMF_ANY)))
  1616.   {
  1617.     ml->cml_Next = fd->fd_MemList;
  1618.     ml->cml_MemoryRegion = reg;
  1619.     ml->cml_MemorySize = size;
  1620.     fd->fd_MemList = ml;
  1621.   }
  1622.   else
  1623.   {
  1624.     FreeMem(reg, size);
  1625.     return XFDCERR_NOMEMORY;
  1626.   }
  1627.   return 0;
  1628. }
  1629.  
  1630. /* Free memory from the memory list. */
  1631. void FreeCrunchMemList(struct FileData *fd, APTR reg)
  1632. {
  1633.   struct CrunchMemList mc, *ml = &mc;
  1634.  
  1635.   if(fd->fd_Flags & XFDCHECKFLAG_NOFREEMEM)
  1636.     return;
  1637.  
  1638.   for(mc.cml_Next = fd->fd_MemList; ml; ml = ml->cml_Next)
  1639.   {
  1640.     if(ml->cml_Next->cml_MemoryRegion == reg)
  1641.     {
  1642.       struct CrunchMemList *m;
  1643.       m = ml->cml_Next;
  1644.       ml->cml_Next = m->cml_Next;
  1645.       FreeMem(m->cml_MemoryRegion, m->cml_MemorySize);
  1646.       FreeMem(m, sizeof(struct CrunchMemList));
  1647.     }
  1648.   }
  1649.  
  1650.   fd->fd_MemList = mc.cml_Next;
  1651. }
  1652.  
  1653. /* Save file, when SAVE option and file was crunched or linked. */
  1654. LONG SaveUncrFile(struct FileData *fd, APTR buf, ULONG size)
  1655. {
  1656.   BPTR filefh, cd;
  1657.   LONG ret = 0, i = 0;
  1658.   UBYTE name[50];
  1659.   UBYTE nbuf[256];
  1660.  
  1661.   if(!(fd->fd_SaveDirL && (fd->fd_Flags & XFDSAVEFLAGS)))
  1662.     return 0;
  1663.  
  1664.   sprintf(name, (fd->fd_LinkNum ? "%s.%ld" : "%s"), FilePart(fd->fd_Name),
  1665.   fd->fd_LinkNum);
  1666.  
  1667.   cd = CurrentDir(fd->fd_SaveDirL);
  1668.  
  1669.   while(!ret && name[i])
  1670.   {
  1671.     for(;name[i] && name[i] != '/'; ++i)
  1672.       nbuf[i] = name[i];
  1673.     if(name[i] == '/')
  1674.     {
  1675.       nbuf[i] = 0;
  1676.       if((filefh = Lock(nbuf, SHARED_LOCK)))
  1677.         UnLock(filefh);
  1678.       else
  1679.       {
  1680.         if((filefh = CreateDir(nbuf)))
  1681.           UnLock(filefh);
  1682.         else
  1683.           ret = XFDCERR_OPENERR;
  1684.       }
  1685.       nbuf[i] = name[i];
  1686.       ++i;
  1687.     }
  1688.   }
  1689.  
  1690.   if(!ret)
  1691.   {
  1692.     if((filefh = Open(name, MODE_NEWFILE)))
  1693.     {
  1694.       if(Write(filefh, buf, size) != size)
  1695.         ret = XFDCERR_READWRITE;
  1696.       Close(filefh);
  1697.     }
  1698.     else
  1699.       ret = XFDCERR_OPENERR;
  1700.   }
  1701.  
  1702.   CurrentDir(cd);
  1703.  
  1704.   return ret;
  1705. }
  1706.  
  1707.